#include<iostream>
#include<string>
#include<unistd.h>
#include<cstdlib>
#include<vector>
#include<time.h>
#include<sys/wait.h>

#include"task.hpp"

using namespace std;


enum
{
    UsageError = 1,
    ArgError,
    PipeError,
};

void Usage(const string& str)
{
    cout<<"Usage"<<str<<"subprocess_Num"<<endl;
}

class Channel
{
public:
    Channel(int wfd,pid_t sub_process_id,string& name)
        :_wfd(wfd)
        ,_sub_process_id(sub_process_id)
        ,_name(name)
    {}

    ~Channel()
    {}
    
    void DebugPrint()
    {
        cout<<"wfd:"<<_wfd;
        cout<<",sub_process_id:"<<_sub_process_id;
        cout<<",name:"<<_name<<endl;
    }

    void Close()
    {
        close(_wfd);
    }

    int wfd(){return _wfd;}
    pid_t pid(){return _sub_process_id;}
    string name(){return _name;}
private:
    int _wfd;
    pid_t _sub_process_id;
    string _name;
};

class ProcessPool
{
public:
    ProcessPool(int sub_process_num)
        :_sub_process_num(sub_process_num)
    {}

    int CreateProcess(work_t work)
    {
        vector<int> fds;
        for(int number = 0;number < _sub_process_num;number++)
        {
            //创建通道
            int pipefd[2]{0};
            int n = pipe(pipefd);
            if(n < 0 ) return PipeError;

            pid_t id = fork();
            if(id == 0)
            {
                for(auto& fd:fds)
                {
                    if(!fds.empty())
                    {
                        close(fd);
                    }
                }
                //子读 关闭写
                close(pipefd[1]);
                //执行任务
                dup2(pipefd[0],0);
                work(pipefd[0]);
                exit(0);
            }
            //父写 关闭读
            string cname = "channel-" + to_string(number); 
            close(pipefd[0]);
            _channels.push_back(Channel(pipefd[1],id,cname));

            fds.push_back(pipefd[1]);
        }

        return 0;
    }

    int NextChannel()
    {
        static int next = 0;
        int c = next;
        next++;
        next%=_channels.size();

        return c;
    }

    void SendTaskCode(int index,uint32_t code)
    {
        cout<<"send code:"<< code << " to:" <<_channels[index].name()<<" pid:"<<_channels[index].pid()<<endl;
        write(_channels[index].wfd(),&code,sizeof(code));
    }

    void Debug()
    {
        for(auto& channel:_channels)
        {
            channel.DebugPrint();
        }
    }

    void KillAll()
    {
        for(auto& channel:_channels)
        {
            channel.Close();

            pid_t pid = channel.pid();
            pid_t rid = waitpid(pid,nullptr,0);
            if(pid == rid)
            {
                cout<<"wait:"<<channel.pid()<<" success..."<<endl;
            }

            cout<<"close done:"<<channel.name()<<" ,pid:"<<channel.pid()<<endl;
        }
    }

    //回收子进程 waitpid
    void Wait()
    {

    }
    ~ProcessPool()
    {}

private:
    int _sub_process_num;
    vector<Channel> _channels;
};


void CtrlProcessPool(ProcessPool* processpool_ptr,int cnt)
{
    while(cnt)
    {
        //a.选择一个进程和通道
        int channel = processpool_ptr->NextChannel();
        //b.选择一个任务
        uint32_t code = NextTask();

        //c.发送任务
        processpool_ptr->SendTaskCode(channel,code);

        sleep(1);
        cnt--;
    }
}

int main(int argc,char* argv[])
{
    //判断命令行参数,有两个，第二个为数字
    if(argc!=2)
    {
        Usage(argv[0]);
        return UsageError;
    }

    //保存需要创建进程的个数
    int sub_process_num = stoi(argv[1]);
    if(sub_process_num <= 0) return ArgError;
    
    srand((uint64_t)time(nullptr));

    //1.创建子进程
    ProcessPool* processpool_ptr = new ProcessPool(sub_process_num);
    processpool_ptr->CreateProcess(worker);
    //processpool_ptr->Debug();
    
    //2.控制子进程
    CtrlProcessPool(processpool_ptr,10);
    
    //3.a.关闭父进程读，子进程退出
    processpool_ptr->KillAll();
    //b.回收子进程
    processpool_ptr->Wait();
    delete processpool_ptr;

    return 0;
}